package mysql

import (
	"fmt"
	"github.com/pkg/errors"
	"strings"
	"xorm.io/builder"
)

var operator = map[string]string{
	"=": "等于", "!=": "不等于", "<>": "不等于", ">": "大于", ">=": "大于等于",
	"<": "小于", "<=": "小于等于", "BETWEEN": "查询连续范围", "IN": "查询指定范围",
	"NOT IN": "不存在指定范围", "LIKE": "模糊查询", "REGEXP": "正则查询",
}

// 单个条件结构体
type Condition struct {
	Column     string        // 条件字段名称
	Operator   string        // mysql 运算符：=、!=（<>）、>、>=、<、<=、BETWEEN、IN、LIKE、REGEXP
	Value      interface{}   // 单个值
	ValueSlice []interface{} // 多个值切片
}

// 子条件结构体
type ChildCondition struct {
	Column    string       // 子查询操作字段
	Operator  string       // 操作类型，固定操作方法类型：=、!=（<>）、>、>=、<、<=、BETWEEN、IN、LIKE、REGEXP
	Table     string       // 子查询关联表名称
	Field     string       // 子查询字段名称
	Condition []*Condition // 子查询的普通 where 条件
}

// 组建单个条件
func buildCondition(condition []*Condition) (condSlice []builder.Cond, err error) {
	condSlice = make([]builder.Cond, 0)
	for _, v := range condition {
		cond, err := buildCond(v)
		if err != nil {
			return nil, err
		}
		condSlice = append(condSlice, cond)
	}
	return condSlice, nil
}

// 组建子查询条件
func buildChildCondition(condition []*ChildCondition) (condSlice []builder.Cond, error error) {
	condSlice = make([]builder.Cond, 0)
	for _, v := range condition {
		cond, err := buildChildCond(v)
		if err != nil {
			return nil, err
		}
		condSlice = append(condSlice, cond)
	}
	return condSlice, nil
}

func buildChildCond(child *ChildCondition) (cond builder.Cond, error error) {
	childSql := ""
	value := make([]interface{}, 0)
	for k, v := range child.Condition {
		// 1. 获取构建条件
		partCond, err := buildCond(v)
		if err != nil {
			return nil, err
		}
		// 2. 获取条件 sql
		sql, val, err := builder.ToSQL(partCond)
		if err != nil {
			return nil, err
		}
		if sql == "" || val == nil {
			return nil, errors.New("child condition is abnormal：" + v.Column)
		}
		// 3. 拼接 sql
		if k != 0 {
			sql = " AND " + sql
		}
		childSql += sql
		// 4. 组装值
		for _, columnValue := range val {
			value = append(value, columnValue)
		}
	}
	cond = builder.Expr(fmt.Sprintf("%s %s (SELECT %s FROM `%s` WHERE %s )",
		child.Column, strings.ToUpper(child.Operator), child.Field, child.Table, childSql), value...)
	return
}

// 组建条件核心方法
func buildCond(v *Condition) (cond builder.Cond, err error) {
	// 1. 判断 mysql 运算符是否合法
	v.Operator = strings.ToUpper(v.Operator)
	if operator[v.Operator] == "" {
		err = errors.New("sql：conditional operator error —— " + v.Operator)
		return
	}
	// 2. 判断字段是否带有 ` 或者是由表连接指定
	if status := strings.Contains(v.Column, "."); status {
		tableColumn := strings.Split(v.Column, ".")
		if status = strings.Contains(tableColumn[0], "`"); !status {
			tableColumn[0] = fmt.Sprintf("`%s`", tableColumn[0])
		}
		if status = strings.Contains(tableColumn[1], "`"); !status {
			tableColumn[1] = fmt.Sprintf("`%s`", tableColumn[1])
		}
		v.Column = fmt.Sprintf("%s.%s", tableColumn[0], tableColumn[1])
	} else {
		if status = strings.Contains(v.Column, "`"); !status {
			v.Column = fmt.Sprintf("`%s`", v.Column)
		}
	}
	// 3. 判断条件类型，获取 cond
	switch v.Operator {
	case "IN":
		cond = builder.In(v.Column, v.ValueSlice...)
	case "NOT IN":
		cond = builder.NotIn(v.Column, v.ValueSlice...)
	case "BETWEEN":
		cond = builder.Expr(fmt.Sprintf("%s %s ? AND ?", v.Column, v.Operator), v.ValueSlice...)
	default:
		cond = builder.Expr(fmt.Sprintf("%s %s ?", v.Column, v.Operator), v.Value)
	}
	return
}
